.NET Core 2 でLiteDBを試す
はじめに
C#製ドキュメント指向NoSQLデータベースのLiteDBを試してみました。 以下、LiteDBの特徴です
- サーバ不要
- 単一ファイルにすべてのデータを格納する
- マルチプロセス・マルチスレッド環境で安全に動作する
- 暗号化対応 (AES/DES)
その他にも色々な特徴があるようです。詳細は公式サイトとGitHubリポジトリを確認してください。
今回はLiteDBを使ってサンプルアプリケーションを作成してみます。
動作環境
- macOS Sierra 10.12.6
- .NET Core SDK 2.1.3
- C# 7.0
- LiteDB 4.1.0
プロジェクト作成
まずプロジェクトファイルを作成します
mkdir -p LiteDBExample cd LiteDBExample dotnet new
次に LiteDB
のパッケージを追加します
dotnet add package LiteDB
ここまででLiteDBを使う準備ができました。 .NET Standardライブラリのみに依存した作りなので導入楽ちんですね。
LiteDBを使う
実際にLiteDBを使ってみましょう。今回は単純なサンプルアプリケーションなので、 Program.cs
にコードを追加していきます。
準備
LiteDBでは1つのコレクションで複数のドキュメントを管理します。
今回はエントリを entries
コレクションに、 タグを tags
に保存するように準備します。
エンティティクラスを作成
ブログのエントリとタグを扱うクラスを用意してみます。
public class BlogTag { public int Id { get; set; } public string Name { get; set; } } public class BlogEntry { public int Id { get; set; } public string Title { get; set; } public string Body { get; set; } public List<BlogTag> Tags { get; set; } // 確認しやすくするため、ToStringメソッドをオーバーライドする public override string ToString() { var tagNames = string.Join(", ", Tags.Select(x => x.Name)); return $"BlogEntry(Id={Id}, Title={Title}, Tags=[{tagNames}])"; } }
BlogEntry.Tagsの扱いを決める
クラス内に非プリミティブ型のメンバを含む場合は、サブドキュメントとして埋め込む方法と、関連ドキュメントとして登録する方法があります。
- サブドキュメントの場合
{ "_id": 1, "Tags": [{ "_id": 1, "Name": "C#" }], ... }
-
関連ドキュメントの場合
{ "_id": 1, "Tags": [{ "$id": 1, "$ref": "tags" }], ... }
{ "_id": 1, "Name": "C#" }
今回は関連ドキュメントとして登録してみます。関連ドキュメントとして登録する場合は、 BsonMapper
に関連を登録します。
var mapper = new BsonMapper(); mapper.Entity<BlogEntry> .DbRef(x => x.Tags, "tags") // Tagsフィールド、tagsコレクションを参照するようにする ;
他にも BsonRef
属性を指定する方法もあるようです。詳細はLiteDBのWikiを確認してください。
データベースに接続
データベースに接続します。
var filename = "litedb-example.db"; using (var db = new LiteDatabase($"Filename={filename};", mapper)) { ...
READMEのサンプル同様の手順で接続したところ、以下のエラーが発生しました。
Unhandled Exception: System.PlatformNotSupportedException: Locking/unlocking file regions is not supported on this platform. Use FileShare on the entire file instead.
同様の問題が issue#787 で報告されていて、connectionStringに Mode=Exclusive
の指定を追加すると動作するようになりました。
var filename = "litedb-example.db"; using (var db = new LiteDatabase($"Filename={filename}; Mode=Exclusive;", mapper)) { ...
コレクションを取得
エントリとタグを登録するためのコレクションを用意します。
var tags = db.GetCollection<BlogTag>("tags"); var entries = db.GetCollection<BlogEntry>("entries");
コレクションにはインデクスを定義することができます。インデクスを定義すると、検索の高速化やユニーク制約による一意性の保証が実現できるので用途に応じて定義しましょう。今回はタグの名前にユニークインデクスを定義します。
tags.EnsureIndex(x => x.Name, unique: true);
以上でコレクションの準備は完了です。
追加
1件追加する場合は Insert
メソッドを、複数件追加する場合は InsertBulk
メソッドを使用します。
// タグを一括追加 var entryTags = new List<BlogTag> { new BlogTag { Name = "C#" }, new BlogTag { Name = ".NET" }, }; tags.InsertBulk(entryTags); // エントリを追加 var entry = new BlogEntry { Title = ".NET CoreでLiteDBを試す", Body = "C#製ドキュメント指向NoSQLデータベースのLiteDBを試してみました。", Tags = entryTags, }; entries.Insert(entry);
正しく反映されているか確認するため、コレクションの登録内容を検索してみます。 BlogEntry.Tags
は関連ドキュメントの読み込みが必要なので、 Include
メソッドを明示的に呼び出します。
Console.WriteLine("-- begin fetch"); foreach (var blogEntry in entries .Include(x => x.Tags).FindAll()) { Console.WriteLine(blogEntry); } Console.WriteLine("-- end fetch");
検索結果
-- begin fetch BlogEntry(Id=1, Title=.NET CoreでLiteDBを試す, Tags=[C#, .NET]) -- end fetch
更新
更新の場合は Update
メソッドを使用します。
entry.Title += " (追記あり)"; entries.Update(entry);
検索結果
-- begin fetch BlogEntry(Id=1, Title=.NET CoreでLiteDBを試す (追記あり), Tags=[C#, .NET]) -- end fetch
削除
削除する場合は Delete
メソッドを使用します。削除の場合は BlogEntry
オブジェクトではなく、Id
の値を指定します。
entries.Delete(entry.Id);
検索結果
-- begin fetch -- end fetch
おわりに
今回は LiteDBの簡単な使い方を紹介しました。 他のライブラリへの依存がなく、単一ファイルで構成されていて手軽に試せるのが非常に魅力的でした。
今後.NETアプリを作るときに組み込んで、実際の使用感を確認してみたいと思います!